/**
 * Copyright (c) 2008, Keisuke Inoue, Syracuse Unviersity
 * All rights reserved.
 *
 */
package edu.syr.iis.web.model;


import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;

import edu.syr.iis.web.util.HibernateUtil;

/**
 * @author kinoue
 *
 */
public class DialogueActManager
{
	/**
	 * Saves a DialogueAct object.
	 */
	public DialogueAct saveDialogueAct(DialogueAct dialogueAct)
	{
		DialogueAct savedDa = null;
		Session session = HibernateUtil.getSessionFactory()
		.getCurrentSession();
		session.beginTransaction();
		try
		{
			savedDa = (DialogueAct) session.merge(dialogueAct);
			System.out.println("Saved a DialogueAct with an id: " + savedDa.dialogueActId);
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return savedDa;
	}


	/**
	 * Update a DialogueAct object.
	 */
	public void updateDialogueAct(DialogueAct dialogueAct)
	{
		System.out.println("Entering saveDialogueAct...");

		Session session = HibernateUtil.getSessionFactory()
		.getCurrentSession();
		session.beginTransaction();
		try
		{            
			session.saveOrUpdate(dialogueAct);
			System.out.println("Updated a DialogueAct with an id: " + dialogueAct.getDialogueActId());
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}

	}


	public DialogueAct getDialogueAct(int dialogueActId)
	{
		DialogueAct dialogueAct = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		System.out.println("---------- Getting dialogueAct of dialogueActId: " + dialogueActId + "----------------");
		try
		{
			dialogueAct = (DialogueAct) session.createQuery(
					"FROM DialogueAct " +
			" WHERE dialogueActId = ?").setInteger(0, dialogueActId).uniqueResult();


			dialogueAct.getMessage();
			int n = dialogueAct.getMessage().getConversation().getNumMessages();
			session.getTransaction().commit();

		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return dialogueAct;
	}

	@SuppressWarnings("unchecked")

	public List<DialogueAct> getDialogueActs()
	{
		List<DialogueAct> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM DialogueAct ORDER BY dialogueActId ").list();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	public List<DialogueAct> getDialogueActsByMessage(Message message, boolean lazy)
	{
		List<DialogueAct> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM DialogueAct WHERE messageId = ? ORDER BY dialogueActId ")
			.setInteger(0, message.getMessageId()).list();

			if (!lazy)
			{
				for (DialogueAct da: list)
				{
					da.getNextDialogueActFunctionLabel();
					da.getPreviousDialogueActFunctionLabel();
				}
			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}


	public List<DialogueAct> getDialogueActs(boolean lazy)
	{
		List<DialogueAct> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM DialogueAct ORDER BY dialogueActId ").list();

			if (!lazy)
			{
				for (DialogueAct da: list)
				{
					da.getNextDialogueActFunctionLabel();
					da.getPreviousDialogueActFunctionLabel();
				}
			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}



	public List<DialogueAct> getDialogueActsByDimension(DialogueActDimension dimension)
	{
		List<DialogueAct> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM DialogueAct WHERE dialogueActDimesion = ? ORDER BY dialogueActId ")
			.setEntity(0, dimension).list();

			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}


	public List<DialogueAct> getDialogueActsBySegement(User user, 
			Message message, int startIndex, int endIndex)
	{
		List<DialogueAct> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM DialogueAct WHERE " +
					"user = ? and " +
					"message = ? and " +
					"startIndex = ? and " +
			"endIndex = ?")		    		
			.setEntity(0, user)
			.setEntity(1, message)
			.setInteger(2, startIndex)
			.setInteger(3, endIndex).list();

			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	public void deleteDialogueAct(DialogueAct da)
	{
		Session session = 
			HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();	
		try
		{
			if (da != null) { 
				session.delete(da);
			}		
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}	
	}


	/**
	 * @param daId
	 */
	public void deleteDialogueAct(int daId)
	{
		Session session = 
			HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();	
		try
		{
			Object toDelete = session.get(DialogueAct.class,new Integer(daId));

			if (toDelete != null) { 
				session.delete(toDelete);
			}		
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}	
	}

	/*
	 * From DialogueActDimensionManager
	 * 
	 */

	/**
	 * Returns list of all DialogueActDimensions of the specified DialogueActScheme sorted by dialogueActDimensionId
	 */
	public List<DialogueActDimension> getDialogueActDimensions(DialogueActScheme dialogueActScheme)
	{
		List<DialogueActDimension> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			String query = "FROM DialogueActDimension WHERE dialogueActSchemeId = ?";
			list = session.createQuery(query).setInteger(0, dialogueActScheme.getDialogueActSchemeId()).list();

			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	/**
	 * Returns list of all DialogueActDimension  sorted by DialogueActDimensionId
	 */
	public List<DialogueActDimension> getDialogueActDimensions()
	{	
		List<DialogueActDimension> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			Criteria criteria = session
			.createCriteria(DialogueActDimension.class)
			.addOrder(Order.asc("dialogueActDimensionId"));
			list = criteria.list();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	public DialogueActDimension getDialogueActDimensionBySchemeAndDimension(String scheme, String dimension)
	{
		DialogueActDimension dialogueActDimension = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			dialogueActDimension = (DialogueActDimension) session.createQuery(
					"FROM DialogueActDimension " +
			" WHERE dialogueActScheme.scheme = ? and dimension = ?")
			.setString(0, scheme).setString(1, dimension).uniqueResult();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return dialogueActDimension;
	}

	public DialogueActDimension getDialogueActDimension(String dimension)
	{
		DialogueActDimension dialogueActDimension = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			Criteria criteria = session.createCriteria(DialogueActDimension.class)
			.add(Restrictions.eq("dimension", dimension));
			dialogueActDimension = (DialogueActDimension) criteria.uniqueResult();			
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return dialogueActDimension;
	}


	public DialogueActDimension getDialogueActDimension(int dialogueActDimensionId)
	{
		DialogueActDimension dialogueActDimension = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			dialogueActDimension = (DialogueActDimension) session.createQuery(
					"FROM DialogueActDimension " +
			" WHERE dialogueActDimensionId = ?").setInteger(0, dialogueActDimensionId).uniqueResult();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return dialogueActDimension;
	}

	/**
	 * Saves a DialogueActDimension object.
	 */
	public void saveDialogueActDimension(DialogueActDimension dialogueActDimension)
	{
		Session session = HibernateUtil.getSessionFactory()
		.getCurrentSession();
		session.beginTransaction();
		try
		{
			session.saveOrUpdate(dialogueActDimension);
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}

	/**
	 * Deletes DialogueActDimension record with matching dialogueActDimensionId 
	 */
	public void deleteDialogueActDimension(int dialogueActDimensionId)
	{
		Session session = 
			HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();	
		try
		{
			session.delete(session.load(DialogueActDimension.class,new Integer(dialogueActDimensionId)));         	    			
			session.flush();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}

	/******************************************************************************
	 * 
	 * From DialogueActLabelManager
	 * 
	 */

	/**
	 * Returns list of all DialogueActLabels of the specified DialogueActScheme sorted by dialogueActLabelId
	 */
	public List<DialogueActLabel> getDialogueActLabelsByScheme(DialogueActScheme dialogueActScheme)
	{
		return getDialogueActLabelsByScheme(dialogueActScheme, true);
	}

	public List<DialogueActLabel> getDialogueActLabelsByScheme(DialogueActScheme dialogueActScheme, boolean lazy)
	{
		List<DialogueActLabel> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			Criteria criteria = session.createCriteria(DialogueActLabel.class);

			DetachedCriteria detachedCriteria = DetachedCriteria.forClass(DialogueActDimension.class);	    
			detachedCriteria.add(Property.forName("dialogueActScheme").eq(dialogueActScheme));

			criteria.add(Restrictions.in("dialogueActDimension", detachedCriteria.getExecutableCriteria(session).list()));
			criteria.addOrder(Order.asc("dialogueActDimension.dialogueActDimensionId"));
			criteria.addOrder(Order.asc("label"));

			if (!lazy) 
			{
				criteria.setFetchMode("dialogueActDimension", FetchMode.JOIN);
				criteria.setFetchMode("dialogueActDimension.dialogueActScheme", FetchMode.JOIN);
			}

			list = criteria.list();

			// This will force the inner-join fetch mode for messages and function/domain
			// (I don't know any other ways to do this.)
			// So that the viewer (.jsp) can access to the fields after the session is closed.
			//
			if (!lazy) 
			{
				for (DialogueActLabel dal: list) 
				{
					dal.getNumLabeled();
					dal.getDialogueActNum();
				}
			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}


	public List<String> getDialogueActLabelStrings(DialogueActAnalysisLevel level, boolean speakerSensitive)
	{
		List<DialogueActLabel> dals = null;
		List<String> labels0 = new ArrayList<String>();
		List<String> labels = new ArrayList<String>();
		
		switch (level)
		{
		case FUNCTION:
			dals = getDialogueActLabels("FUNCTION");
			for (DialogueActLabel dal: dals)
				labels0.add(dal.getLabelNoSpace());
			break;
		case PART_DOMAIN:
			dals = getDialogueActLabels("DOMAIN");
			for (DialogueActLabel dal: dals)
				if (! labels0.contains(dal.getPartLabelNoSpace()))
					labels0.add(dal.getPartLabelNoSpace());
			break;
		case FULL_DOMAIN:
			dals = getDialogueActLabels("DOMAIN");
			for (DialogueActLabel dal: dals)
				labels0.add(dal.getLabelNoSpace());
			break;
		}
	
		if (speakerSensitive)
			for (String label0 : labels0)
			{
				labels.add(DialogueActLabel.U_PREFIX + label0);
				labels.add(DialogueActLabel.L_PREFIX + label0);
			}
		else
			labels = labels0;
		
		return labels;
	}
	
	public List<String> getDialogueActLabelStrings(String dimension)
	{
		DialogueActDimension dad = getDialogueActDimension(dimension); 
		List<DialogueActLabel> dals = getDialogueActLabels(dad, false);
		List<String> labels = new ArrayList<String>();

		for (DialogueActLabel dal: dals)
			labels.add(dal.getLabel());

		return labels;
	}

	
	public List<String> getDialogueActLabelStrings(DialogueActDimension dimension)
	{
		List<DialogueActLabel> dals = getDialogueActLabels(dimension, false);
		List<String> labels = new ArrayList<String>();

		for (DialogueActLabel dal: dals)
			labels.add(dal.getLabel());

		return labels;
	}


	/**
	 * Returns list of all DialogueActLabels of the specified DialogueActDimension sorted by dialogueActLabelId
	 */
	public List<DialogueActLabel> getDialogueActLabels(String dimension)
	{
		List<DialogueActLabel> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		DialogueActDimension dad = getDialogueActDimension(dimension);
		try
		{
			String query = "FROM DialogueActLabel WHERE dialogueActDimensionId = ?";
			list = session.createQuery(query).setInteger(0, dad.getDialogueActDimensionId()).list();

			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}
	
	
	/**
	 * Returns list of all DialogueActLabels of the specified DialogueActDimension sorted by dialogueActLabelId
	 */
	public List<DialogueActLabel> getDialogueActLabels(DialogueActDimension dialogueActDimension)
	{
		List<DialogueActLabel> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			String query = "FROM DialogueActLabel WHERE dialogueActDimensionId = ?";
			list = session.createQuery(query).setInteger(0, dialogueActDimension.getDialogueActDimensionId()).list();

			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	public List<DialogueActLabel> getDialogueActLabels()
	{
		return getDialogueActLabels(true);
	}

	public List<DialogueActLabel> getDialogueActLabels(boolean lazy)
	{
		return getDialogueActLabels(null, lazy);
	}

	public List<DialogueActLabel> getDialogueActLabels(DialogueActDimension dialogueActDimension, boolean lazy)
	{
		List<DialogueActLabel> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			DetachedCriteria detachedCriteria = DetachedCriteria.forClass(DialogueActScheme.class)
			.addOrder(Order.asc("dialogueActShemeId"));

			Criteria criteria = session.createCriteria(DialogueActLabel.class)
			// .addOrder(Order.asc("dialogueActDimension.dialogueActScheme.dialogueActSchemeId"))
			.addOrder(Order.asc("dialogueActDimension.dialogueActDimensionId"))
			.addOrder(Order.asc("label"));

			if (dialogueActDimension != null)
				criteria.add(Restrictions.eq("dialogueActDimension", dialogueActDimension));

			if (!lazy) 
			{
				criteria.setFetchMode("dialogueActDimension", FetchMode.JOIN);
				criteria.setFetchMode("dialogueActDimension.dialogueActScheme", FetchMode.JOIN);
			}

			list = criteria.list();

			if (!lazy)
			{
				for (DialogueActLabel dal: list)
				{						
					dal.getNumLabeled();
					dal.getDialogueActNum();
				}

			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}



	/**
	 * Returns list of all the DialogueActLabels with the given Scheme and Dimension 
	 * @param dimension 
	 * @param scheme 
	 */
	public List<DialogueActLabel> getDialogueActLabelsBySchemeAndDimension(String scheme, String dimension)
	{
		List<DialogueActLabel> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			String query = "FROM DialogueActLabel " +
			"  WHERE dialogueActDimension.dialogueActScheme.scheme = ? and dialogueActDimension.dimension = ?" +
			"  ORDER BY label";

			list = session.createQuery(query).setString(0, scheme).setString(1, dimension).list();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}




	public DialogueActLabel getDialogueActLabel(int id, boolean lazy)
	{
		DialogueActLabel dialogueActLabel = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			Criteria criteria = session.createCriteria(DialogueActLabel.class)
			.add(Restrictions.eq("dialogueActLabelId", id));

			if (!lazy)
			{
				criteria.setFetchMode("dialogueActDimension", FetchMode.JOIN);
				criteria.setFetchMode("dialogueActDimension.dialogueActScheme", FetchMode.JOIN);				
			}

			dialogueActLabel = (DialogueActLabel) criteria.uniqueResult();

			if (!lazy) 
			{
				dialogueActLabel.getMessages().size();
				dialogueActLabel.getFunctionDialogueActs().size();
				dialogueActLabel.getDomainDialogueActs().size();				
			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return dialogueActLabel;
	}


	public DialogueActLabel getDialogueActLabel(int dialogueActLabelId)
	{
		return getDialogueActLabel(dialogueActLabelId, true);
	}

	/**
	 * Saves a DialogueActLabel object.
	 */
	public void saveDialogueActLabel(DialogueActLabel dialogueActLabel)
	{
		Session session = HibernateUtil.getSessionFactory()
		.getCurrentSession();
		session.beginTransaction();
		try
		{
			session.saveOrUpdate(dialogueActLabel);
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}


	/**
	 * Deletes DialogueActLabel record with matching dialogueActLabelId 
	 */
	public void deleteDialogueActLabel(int dialogueActLabelId)
	{
		Session session = 
			HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();	
		try
		{
			Object toDelete = session.get(DialogueActLabel.class,new Integer(dialogueActLabelId));

			if (toDelete != null) { 
				session.delete(toDelete);
			}

			session.flush();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}

}
